package com.alex.service;

import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch._types.aggregations.StringTermsBucket;
import co.elastic.clients.elasticsearch._types.query_dsl.FieldAndFormat;
import co.elastic.clients.elasticsearch._types.query_dsl.MatchQuery;
import co.elastic.clients.elasticsearch._types.query_dsl.Query;
import co.elastic.clients.elasticsearch.core.SearchRequest;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.elasticsearch.core.search.Hit;
import com.alex.common.config.IndexConfig;
import com.alex.entity.AggsKeyValue;
import com.alex.entity.ArticleEntity;

import com.yuntsg.paperana.utils.esutils.EsServerEntity;
import com.alex.utils.EsClient;
import com.alex.utils.StringUtil;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

import static java.util.stream.Collectors.toList;

/**
 * ZFL
 * 13864677931
 * 2690370788@qq.com
 * 2023-02-10
 */
public class AllQueryBasicService {

    public static ElasticsearchClient client = EsClient.client();

    public static void main(String[] args) throws IOException {
        Query query = MatchQuery.of(i -> i.field("str").query("Grafts showed a large intimal thickening composed of several layers of smooth muscle cells "))._toQuery();
        List<Hit<EsServerEntity>> list = allQuery("text_str_prod", query, null, EsServerEntity.class);
        List<EsServerEntity> covertList = coventList(list);
        for (EsServerEntity one : covertList) {
            String str = one.getStr();
            System.out.println(111 + str);
        }

    }

    public static List<EsServerEntity> allQueryYuLiao(Query query, Integer from, Integer size) throws IOException {


        SearchResponse<EsServerEntity> response = client.search(s -> s
                        .index(IndexConfig.YU_LIAO)
                        .fields(Arrays.asList(
                                FieldAndFormat.of(builder -> builder.field("file_id")),
                                FieldAndFormat.of(builder -> builder.field("sentence")),
                                FieldAndFormat.of(builder -> builder.field("database_type")),
                                FieldAndFormat.of(builder -> builder.field("str")),
                                FieldAndFormat.of(builder -> builder.field("pmid_ut")),
                                FieldAndFormat.of(builder -> builder.field("sub_project")),
                                FieldAndFormat.of(builder -> builder.field("table_id"))))
                        .from(0)
                        .size(5)
                        .highlight(h -> h.preTags("<span style=\"color:red\">").postTags("</span>").fields("str", highlightFieldBuilder -> highlightFieldBuilder))
                        .query(query),
                EsServerEntity.class
        );

//        SearchResponse<EsServerEntity> response = client.search(new SearchRequest.Builder().index(IndexConfig.YU_LIAO)
//                .query(query).highlight(i -> i.preTags("<span style=\"color:red\">").postTags("</span>").fields("str", o -> o))
//                .from(from).size(size).build(), EsServerEntity.class);

        List<Hit<EsServerEntity>> hits = response.hits().hits();
        for (Hit<EsServerEntity> hit : hits) {
            EsServerEntity source = hit.source();
            if (source == null) {
                return null;
            }
            Map<String, List<String>> highlight = hit.highlight();
            highlight.forEach((k, v) -> {
                if (k.equals("str")) {
                    source.setStr(v.get(0));
                }
            });
        }
        return coventList(hits);
    }

    /**
     * 指定返回数量
     *
     * @param index    索引名称
     * @param query    检索条件
     * @param from     当前页
     * @param size     每页显示数量
     * @param includes 要返回的字段
     * @param cla      以Bean类型接收
     * @param <T>
     * @return
     * @throws IOException
     */
    public static <T> List<Hit<T>> allQuery(String index, Query query, Integer from, Integer size, List<String> includes, Class<T> cla) throws IOException {
        SearchRequest.Builder builder = new SearchRequest.Builder();
        builder.index(index)
                .query(query)
                .from(from).size(size);
        if (includes != null) {
            builder.source(sourceConfigBuilder -> sourceConfigBuilder
                    .filter(sourceFilterBuilder -> sourceFilterBuilder
                            .includes(includes)));
        }
        SearchResponse<T> response = client.search(builder.build(), cla);
        List<Hit<T>> hits = response.hits().hits();
        return hits;
    }

    /**
     * 带排序
     *
     * @param index
     * @param query
     * @param from
     * @param size
     * @param includes
     * @param shortBy
     * @param shortType
     * @param cla
     * @param <T>
     * @return
     * @throws IOException
     */
    public static <T> List<Hit<T>> allQueryShort(String index, Query query, Integer from, Integer size, List<String> includes, String shortBy, Integer shortType, Class<T> cla) throws IOException {
        SearchRequest.Builder builder = new SearchRequest.Builder();
        builder.index(index)
                .query(query)
                .from(from).size(size);
        if (includes != null) {
            builder.source(sourceConfigBuilder -> sourceConfigBuilder
                    .filter(sourceFilterBuilder -> sourceFilterBuilder
                            .includes(includes)));
        }
        if (StringUtil.isNotNull(shortBy)) {
            builder.sort(sortOptionsBuilder -> sortOptionsBuilder
                    .field(fieldSortBuilder -> fieldSortBuilder
                            .field(shortBy).order(shortType == 0 ? SortOrder.Asc : SortOrder.Desc)));
        }
        SearchResponse<T> response = client.search(builder.build(), cla);
        List<Hit<T>> hits = response.hits().hits();
        return hits;
    }

    /**
     * 返回response ,通常需要手动处理分页的时候进行
     * long value = response.hits().total().value();
     * 这个可以获取到命中条数
     *
     * @param index
     * @param query
     * @param from
     * @param size
     * @param includes
     * @param cla
     * @return
     * @throws IOException
     */
    public static <T> SearchResponse<T> allQueryRes(String index, Query query, Integer from, Integer size, List<String> includes, Class<T> cla) throws IOException {
        SearchRequest.Builder builder = new SearchRequest.Builder();
        builder.index(index)
                .query(query)
                .trackTotalHits(k -> k.enabled(true))
                .from(from).size(size);
        if (includes != null) {
            builder.source(sourceConfigBuilder -> sourceConfigBuilder
                    .filter(sourceFilterBuilder -> sourceFilterBuilder
                            .includes(includes)));
        }

        return client.search(builder.build(), cla);
    }

    /**
     * 默认返回前十个
     *
     * @param index
     * @param query
     * @param includes
     * @param cla
     * @param <T>
     * @return
     * @throws IOException
     */
    public static <T> List<Hit<T>> allQuery(String index, Query query, List<String> includes, Class<T> cla) throws IOException {
        SearchRequest.Builder builder = new SearchRequest.Builder();
        builder.index(index)
                .query(query)
                .from(0).size(10);
        if (includes != null) {
            builder.source(sourceConfigBuilder -> sourceConfigBuilder
                    .filter(sourceFilterBuilder -> sourceFilterBuilder
                            .includes(includes)));
        }
        SearchResponse<T> response = client.search(builder.build(), cla);
        List<Hit<T>> hits = response.hits().hits();
        return hits;
    }


    public static <T> List<T> coventList(List<Hit<T>> hits) {
        List<T> collect = hits.stream().map(i -> i.source()).collect(toList());
        return collect;
    }

    /**
     * 公共的分组方法 String Long
     *
     * @param query
     * @param str
     * @return
     * @throws Exception
     */
    public List<AggsKeyValue> aggStrPublic(Query query, String str) throws Exception {
        ElasticsearchClient client = EsClient.client();
        SearchResponse<ArticleEntity> response = client.search(searchRequestBuilder -> searchRequestBuilder
                        .index(IndexConfig.CORE_INDEX)
                        .query(query)
                        .aggregations("my_aggre", aggregationBuilder -> aggregationBuilder
                                .terms(termsAggregationBuilder -> termsAggregationBuilder
                                        .field(str)
                                )
                        ).size(30)
                , ArticleEntity.class);
        List<AggsKeyValue> list = new ArrayList<>();
        for (StringTermsBucket bucket : response.aggregations().get("my_aggre").sterms().buckets().array()) {
            long value = bucket.docCount();
            list.add(new AggsKeyValue(bucket.key().stringValue(), value));
        }
        return list;
    }

    public List<AggsKeyValue> aggStrPublic300(Query query, String str) throws Exception {
        ElasticsearchClient client = EsClient.client();
        SearchResponse<ArticleEntity> response = client.search(searchRequestBuilder -> searchRequestBuilder
                        .index(IndexConfig.CORE_INDEX)
                        .query(query)
                        .aggregations("my_aggre", aggregationBuilder -> aggregationBuilder
                                .terms(termsAggregationBuilder -> termsAggregationBuilder
                                        .field(str).size(300)
                                )
                        )
                , ArticleEntity.class);
        List<AggsKeyValue> list = new ArrayList<>();
        for (StringTermsBucket bucket : response.aggregations().get("my_aggre").sterms().buckets().array()) {
            long value = bucket.docCount();
            list.add(new AggsKeyValue(bucket.key().stringValue(), value));
        }
        return list;
    }

    public static List<Integer> checkPage(Integer page, Integer limit) {
        if (page == null) {
            page = 1;
        }
        if (limit == null) {
            limit = 20;
        }
        List<Integer> list = new ArrayList<>();

        list.add((page - 1) * limit);
        //list.add(((page - 1) * limit) + limit);
        list.add(limit);
        return list;
    }

}
